﻿using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using Esponce.Common;
#if WINRT
using Windows.UI;
using Windows.Foundation;
#else
using System.Windows.Media;
using System.Windows;
#endif

namespace Esponce.QRCode
{
	[DataContract(Name = "qrcode", Namespace = "")]
	public partial class QRCodeModel : INotifyPropertyChanged
	{
		#region Public properties
		/// <summary>
		/// Gets or sets a message to be written or read from QR Code.
		/// </summary>
		[DataMember(Name = "content", IsRequired = false, EmitDefaultValue = false)]
		public string Content
		{
			get
			{
				return this.content;
			}
			set
			{
				if (this.content != value)
				{
					this.content = value;
					OnPropertyChanged("Content");
				}
			}
		}
		private string content;

		/// <summary>
		/// Gets or sets the output format.
		/// </summary>
		[DataMember(Name = "format", IsRequired = false, EmitDefaultValue = false)]
		public string Format
		{
			get
			{
				return this.format;
			}
			set
			{
				if (this.format != value)
				{
					this.format = value;
					OnPropertyChanged("Format");
				}
			}
		}
		private string format;

		/// <summary>
		/// Gets or sets a QR Code module size in pixels.
		/// </summary>
		[DataMember(Name = "size", IsRequired = false, EmitDefaultValue = false)]
		public int? Size
		{
			get
			{
				return this.size;
			}
			set
			{
				if (this.size != value)
				{
					this.size = value;
					OnPropertyChanged("Size");
				}
			}
		}
		private int? size;

		/// <summary>
		/// Gets or sets overall image size in pixels. Both width and height must be equal.
		/// Note that this parameter overrides the "Size" property.
		/// </summary>
		public Size ImageSize
		{
			get
			{
				return this.imageSize;
			}
			set
			{
				if (this.imageSize != value)
				{
					this.imageSize = value;
					OnPropertyChanged("ImageSize");
				}
			}
		}
#if WINRT
		private Size imageSize = Windows.Foundation.Size.Empty;
#else
		private Size imageSize = System.Windows.Size.Empty;
#endif

		/// <summary>
		/// Gets or sets a QR Code version. Values 1-40 or null to be automatically determined.
		/// </summary>
		[DataMember(Name = "version", IsRequired = false, EmitDefaultValue = false)]
		public int? Version
		{
			get
			{
				return this.version;
			}
			set
			{
				if (this.version != value)
				{
					if (value == null || value == -1 || value == 0 || (value >= 1 && value <= 40))
					{
						this.version = value;
						OnPropertyChanged("Version");
					}
					else
					{
						throw new ArgumentException("Version must be 1-40 or null to be automatically determined!");
					}
				}
			}
		}
		private int? version;

		/// <summary>
		/// Gets or sets the padding value in modules.
		/// </summary>
		[DataMember(Name = "padding", IsRequired = false, EmitDefaultValue = false)]
		public int? Padding
		{
			get
			{
				return this.padding;
			}
			set
			{
				if (this.padding != value)
				{
					this.padding = value;
					OnPropertyChanged("Padding");
				}
			}
		}
		private int? padding;

		[DataMember(Name = "em", IsRequired = false, EmitDefaultValue = false)]
		public string EncodeModeString
		{
			get
			{
				return this.encodeModeString;
			}
			set
			{
				if (this.encodeModeString != value)
				{
					this.encodeModeString = value;
					OnPropertyChanged("EncodeModeString");
					OnPropertyChanged("EncodeMode");
				}
			}
		}
		private string encodeModeString;

		/// <summary>
		/// Gets or sets the encoding mode.
		/// </summary>
		public QREncodeMode EncodeMode
		{
			get
			{
				if (this.EncodeModeString != null)
				{
					string em = this.EncodeModeString.ToLower();
					switch (em)
					{
						case "byte":
							return QREncodeMode.Byte;

						case "alphanumeric":
							return QREncodeMode.AlphaNumeric;

						case "numeric":
							return QREncodeMode.Numeric;
					}
				}

				return QREncodeMode.Default;
			}
			set
			{
				this.EncodeModeString = (value != QREncodeMode.Default ? value.ToString().ToLower() : null);
			}
		}

		[DataMember(Name = "ec", IsRequired = false, EmitDefaultValue = false)]
		public string ErrorCorrectionString
		{
			get
			{
				return this.errorCorrectionString;
			}
			set
			{
				if (this.errorCorrectionString != value)
				{
					this.errorCorrectionString = value;
					OnPropertyChanged("ErrorCorrectionString");
					OnPropertyChanged("ErrorCorrection");
				}
			}
		}
		private string errorCorrectionString;

		/// <summary>
		/// Gets or sets the error correction level. Message can be recovered if QR code is partially damaged,
		/// recovery percent defines the error correction level (up to 30%).
		/// </summary>
		public QRErrorCorrection ErrorCorrection
		{
			get
			{
				if (this.ErrorCorrectionString != null)
				{
					string ec = this.ErrorCorrectionString.ToLower();
					switch (ec)
					{
						case "l":
							return QRErrorCorrection.L;

						case "m":
							return QRErrorCorrection.M;

						case "h":
							return QRErrorCorrection.H;

						case "q":
							return QRErrorCorrection.Q;
					}
				}

				return QRErrorCorrection.Unknown;
			}
			set
			{
				this.ErrorCorrectionString = (value == QRErrorCorrection.Default || value == QRErrorCorrection.Unknown ? null : value.ToString().ToLower());
			}
		}

		[DataMember(Name = "foreground", IsRequired = false, EmitDefaultValue = false)]
		public string ForegroundString
		{
			get
			{
				return this.foregroundString;
			}
			set
			{
				if (this.foregroundString != value)
				{
					this.foregroundString = value;
					OnPropertyChanged("ForegroundString");
					OnPropertyChanged("Foreground");
				}
			}
		}
		private string foregroundString;

		/// <summary>
		/// Gets or sets ARGB color for foreground.
		/// </summary>
		public Color? Foreground
		{
			get
			{
				Color color;
				if (Helper.TryGetColor(this.ForegroundString, out color))
				{
					return color;
				}
				return null;
			}
			set
			{
				if (value == null)
				{
					this.ForegroundString = null;
				}
				else
				{
					this.ForegroundString = value.Value.ToHexString(true);
				}
			}
		}

		[DataMember(Name = "background", IsRequired = false, EmitDefaultValue = false)]
		public string BackgroundString
		{
			get
			{
				return this.backgroundString;
			}
			set
			{
				if (this.backgroundString != value)
				{
					this.backgroundString = value;
					OnPropertyChanged("BackgroundString");
					OnPropertyChanged("Background");
				}
			}
		}
		private string backgroundString;

		/// <summary>
		/// Gets or sets ARGB color for background.
		/// </summary>
		public Color? Background
		{
			get
			{
				Color color;
				if (Helper.TryGetColor(this.BackgroundString, out color))
				{
					return color;
				}
				return null;
			}
			set
			{
				if (value == null)
				{
					this.BackgroundString = null;
				}
				else
				{
					this.BackgroundString = value.Value.ToHexString(true);
				}
			}
		}

		/// <summary>
		/// Gets or sets an URL shortener service.
		/// </summary>
		[DataMember(Name = "shorten", IsRequired = false, EmitDefaultValue = false)]
		public string Shorten
		{
			get
			{
				return this.shorten;
			}
			set
			{
				if (this.shorten != value)
				{
					this.shorten = value;
					OnPropertyChanged("Shorten");
				}
			}
		}
		private string shorten;

		/// <summary>
		/// Gets or sets a number of modules in row or column.
		/// </summary>
		[DataMember(Name = "dimension", IsRequired = false, EmitDefaultValue = false, Order = 11)]
		public int? Dimension
		{
			get
			{
				return this.dimension;
			}
			set
			{
				if (this.dimension != value)
				{
					this.dimension = value;
					OnPropertyChanged("Dimension");
				}
			}
		}
		private int? dimension;

		/// <summary>
		/// Gets or sets the capacity of QR Code - maximum possible length of bytes to be stored in QR Code.
		/// </summary>
		[DataMember(Name = "capacity", IsRequired = false, EmitDefaultValue = false, Order = 12)]
		public int? Capacity
		{
			get
			{
				return this.capacity;
			}
			set
			{
				if (this.capacity != value)
				{
					this.capacity = value;
					OnPropertyChanged("Capacity");
				}
			}
		}
		private int? capacity;

		/// <summary>
		/// Gets or sets length of stored content in bytes.
		/// </summary>
		[DataMember(Name = "length", IsRequired = false, EmitDefaultValue = false, Order = 13)]
		public int? Length
		{
			get
			{
				return this.length;
			}
			set
			{
				if (this.length != value)
				{
					this.length = value;
					OnPropertyChanged("Length");
				}
			}
		}
		private int? length;
		#endregion

		#region INotifyPropertyChanged Members
		public event PropertyChangedEventHandler PropertyChanged;
		protected virtual void OnPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
		#endregion
	}
}